Rails の クエリチューニングの記憶を取り戻すメモ
会社のesa で書いてたやつの転記したメモ(書いたコードとかクエリは省略してる)
Rails の N+1 問題対応をしてクエリチューニングの仕方を忘れまくっていた。またわからなくなった時のためにメモを残す
読んだ記事
eager_load と preload について
何をやっている?
アソシエーションをまとめてキャッシュしてくれる
eager loading と呼ばれるもので Rails 以外にもある概念
この単語だけでググると Laravel の記事も上に出てくる
eager_load がやること
指定したアソシエーションをLEFT JOINで取得しキャッシュする
1つのクエリでまとめてキャッシュする
LEFT JOIN とは?
左外部結合(テーブル1の全データを取り出して、それにテーブル2のデータをくっつける)
preload がやること
指定したアソシエーションを別クエリで取得してキャッシュする
IN 句を使用した別のクエリを発行してキャッシュする
IN句って?→複数の値を条件にして絞り込む
使い分けのイメージ
belongs_to , has_one などのN対1、1対1のアソシエーションの時
eager_load を使って LEFT JOIN でまとめて取得する
N対1, 1対1の関係なら外部結合しても取得するレコード数に変わりなく1クエリで取得できて効率が良いため
has_many や多対多の関係の時
preload を使ってクエリを分割する
LEFT JOIN で一括取得すると大量のレコードを1度で取得してしまいスロークエリになる可能性があるため
データ量が大きいテーブルに対して結合を行うと1回分のクエリが重くなるのでクエリ分割して事前読み込みをした方が早いという考え方
主テーブルのレコード数が多い場合は、IN句が大きくなってしまう問題が起きるため、DB側で設定値を確認する必要がある
関連先の絞り込みをしたいときは eager_load を使う(preload では絞り込みするとエラーになる)
クエリを作る時に考えるべきこと
発行されるSQLがどんな形なのかログで確認する
ActiveRecord に頼りすぎて SQL のことを考えずに書いてしまいがちな人生を送っていた……
先に SQLを組み立ててイメージする人もいれば、preload と eager_load どっちを使えばいいかを先に考える人もいるらしいと社内の人から聞いた
preload, eager_load を使う時にどういう意図で入れるものか理解した上で入れる
preload でとりあえずキャッシュできてうれしい〜となっても、それってほんとに preload でやる意味ある?アソシエーションを見て確認する